/**
 * Copyright 2006 gworks.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 */
package au.com.gworks.jump.app.wiki.client.navigation;

import java.util.HashMap;
import java.util.Map;

import org.javaongems.client.Command;
import org.javaongems.client.Gem;
import org.javaongems.client.forms.Form;
import org.javaongems.client.forms.FormController;
import org.javaongems.client.rt.io.PathUtils;
import org.javaongems.client.stdctrls.MenuItem;
import org.javaongems.client.stdctrls.MenuBar.MenuBarListener;
import org.javaongems.client.winctrls.BreadcrumbBar;
import org.javaongems.client.winctrls.ListView;
import org.javaongems.client.winctrls.ListViewListener;
import org.javaongems.client.winctrls.BreadcrumbBar.Crumb;

import au.com.gworks.jump.app.wiki.client.service.WikiRpc;
import au.com.gworks.jump.app.wiki.client.service.WikiRpcAsync;

import com.google.gwt.user.client.ui.SourcesTabEvents;
import com.google.gwt.user.client.ui.TabListener;

public class ExplorerController extends FormController implements
		ListViewListener, // for listview changes
		TabListener,
		ExplorerToolbar.ToolbarListener, 
		BreadcrumbBar.Listener ,
		MenuBarListener
		{
	private ExplorerForm window;
	private WikiRpc.ExplorerInfo model;
	private String 	namespace, folderPath;
	private Integer revision;
	private boolean isHeadRevision;
	private boolean useHeadRevision;
	private String revSpecifier;
	
	public void setUp(Map config) {
		super.setUp(config);
		window = new ExplorerForm(this);
		setForm(window);
		int[] leftTopWidthHeight = (int[]) config.get("top.left.width.height.array");
		if (leftTopWidthHeight == null)
			leftTopWidthHeight = new int[] {0, 0, 350, 200};
		leftTopWidthHeight[2] = 760;
		leftTopWidthHeight[3] = (int) (leftTopWidthHeight[3] * 0.8);
		window.place(leftTopWidthHeight);
		initialiseContext();
	}
	
	private void initialiseContext() {
		// we initialise to the context of the page. after this point things can change
		String rev = Gem.stone.getGemPropertyAsString("requestPathInfo.revision", null);
		revision = new Integer(rev);
		namespace = Gem.stone.getGemPropertyAsString("requestPathInfo.namespace", null);
		folderPath = Gem.stone.getGemPropertyAsString("requestPathInfo.path", null);
		String parentPath = Gem.stone.getGemPropertyAsString("requestPathInfo.ra.parentPath", null);
		String pathStatus = Gem.stone.getGemPropertyAsString("requestPathInfo.pathStatus", null);
		String headRev = Gem.stone.getGemPropertyAsString("isHeadRevision", null);
		if ("2".equals(pathStatus))
			folderPath = parentPath;
		isHeadRevision = Boolean.valueOf(headRev).booleanValue();
		useHeadRevision = isHeadRevision;
		revSpecifier = Gem.stone.getGemPropertyAsString("requestPathInfo.revSpecifier", null);
		if ("null".equals(revSpecifier) || "".equals(revSpecifier))
			revSpecifier = null;
		window.setContext(namespace, folderPath, revision);
	}
	
	public void run() {
		NavInfo beforeAndAfter = constructNavInfoFromCurrentCtx();
		NavigationCommand initCmd = new NavigationCommand(beforeAndAfter, beforeAndAfter);
		Gem.stone.onTransition(initCmd);
		super.run();
	}

	public void onSelection(MenuItem selection) {
		if (selection == window.fileCloseMenuItem) 
			window.close();
		else if (selection == window.fileUpldMenuItem) {
			if (Gem.stone.isDebugEnabled()) Gem.stone.log("file upload menu selected");
			showUploader();
		}
	}
	
	public void onFormShow() {
		super.onFormShow();
		onFormRefresh();
	}
	
	public void onFormResized() {
		super.onFormResized();
		window.resizeListView();
	}
	
	public void onFormRefresh() {
		super.onFormRefresh();
		WikiRpcAsync rpc = (WikiRpcAsync) Gem.stone.openService(WikiRpc.SERVICE_CTX);
		if (isHeadRevision)
			revision = null;
		formLoadCallbackDecoration.setStatus("querying filesystem...");
		rpc.exploreFolder(namespace, revision, folderPath, callback);	// always want to view latest
	}
	
	public void onSuccess(Object result) {
		model = (WikiRpc.ExplorerInfo) result;
		updateRevisionStateAndRefreshWindow();
	}
	
	private void showUploader() {
		FileUpload.Controller fu = new FileUpload.Controller();
		HashMap info = new HashMap();
		info.put("folderPath", folderPath);
		info.put("explorerForm", window);
		fu.setUp(info);
		fu.run();
	}
	
	// we are no longer bound the context of the page
	private void updateRevisionStateAndRefreshWindow() {
		namespace = model.namespace;
		revision = model.timedRevision;
		folderPath = model.folderPath;
		revision = model.timedRevision;
		window.setExplorerModel(model);
		window.setContext(namespace, folderPath, revision);
		window.show();
	}

	public void onClick(ListView vw, int dataRow, int col) {
	}

	public void onDblClick(ListView vw, int dataRow, int col) {
		String[] storeFolder = new String[1];
		WikiRpc.ResourceAttrInfo[] storeRes = new WikiRpc.ResourceAttrInfo[1]; 
		boolean resType = getFolderResourceRowMapper(dataRow, storeFolder, storeRes);
		String newPath = (resType ? storeRes[0].getAbsolutePath(): storeFolder[0]);
		if (resType) 
			Gem.stone.openParameterisedUrl(new String[] {namespace, revSpecifier, newPath});
		else {
			moveToFolder(PathUtils.appendSlashIfRequired(folderPath) + newPath);
		}
	}

	private void moveToFolder(String newFolderPath) {
		NavInfo before = constructNavInfoFromCurrentCtx();
		folderPath = newFolderPath;
		NavInfo after = constructNavInfoFromCurrentCtx();
		NavigationCommand cmd = new NavigationCommand(before, after);
		cmd.execute();
	}

	public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) {
		return true;
	}

	public void onTabSelected(SourcesTabEvents sender, int tabIndex) {
		window.switchToTab(tabIndex);
	}
	
	public void onLoadSignPostCrumbs(Crumb crumb) {
		Gem.stone.log("need to dynamically load crumbs signpost: " + crumb.getText());
	}

	public void onSelect(Crumb crumb) {
		moveToFolder(crumb.reference);
	}

	public Object getModel() {
		return model;
	}
	
	public boolean getFolderResourceRowMapper(int row, String[] storeFolder, WikiRpc.ResourceAttrInfo[] storeRes) {
		boolean ret = true;
		int fldrSz = model.subFolders.length;
		if (row < fldrSz) {	// its a resource rqst
			ret = false;
			if (storeFolder != null)
				storeFolder[0] = model.subFolders[row];
		} else {
			if (storeRes != null)
				storeRes[0] = model.resources[row-fldrSz];
		}
		return ret;
	}
	
	private NavInfo constructNavInfoFromCurrentCtx() {
		return new NavInfo(revision, folderPath, useHeadRevision);
	}
	
	private class NavigationCommand implements Command {
		public NavInfo origLeg;
		public NavInfo newLeg;
		
		public NavigationCommand(NavInfo ol, NavInfo nl) {
			origLeg = ol;
			newLeg = nl;
		}
		
		public void undo() {
			navigateTo(origLeg);
		}

		public void redo() {
			navigateTo(newLeg);
		}

		public void execute() {
			onFormRefresh();
			Gem.stone.onTransition(this);
		}
		
		private void navigateTo(NavInfo toSet) {
			if (!isWindowStillActive())
				return;
			folderPath = toSet.folderPath;
			revision = toSet.revision;
			useHeadRevision = toSet.useHeadRevision;
			onFormRefresh();
		}
		
		private boolean isWindowStillActive() {
			Form wnd = getForm();
			boolean ret = (wnd != null && wnd.isOpen());
			return ret;
		}
	}
	
	static private class NavInfo {
		public String 	folderPath;
		public Integer	revision;
		public boolean 	useHeadRevision;
		public NavInfo(Integer rev, String path, boolean head) {
			revision = rev;
			folderPath = path;
			useHeadRevision = head;
		}
	}
}